#ifndef __GMATH_H__
#define __GMATH_H__

template  <typename T> 
class  CTPoint2D
{
	typedef CTPoint2D<T> point_type;
public:
	typedef T value_type;

	/*!
	\brief
	Constructor for a 2D point.
	*/

	CTPoint2D(void) {}
	CTPoint2D(T _x, T _y):d_X(_x), d_Y(_y){}

	void zero()
	{
		d_X = 0;
		d_Y = 0;
	}
	/*!
	\brief
	Destructor for a 2D point.
	*/
	~CTPoint2D(void){}


	void set( T _x, T _y ){
		d_X = _x;
		d_Y = _y;
	}

	void normalize( float _fVal ){
		float t_factor = _fVal / (float)sqrt(d_X*d_X + d_Y*d_Y );
		d_X *= t_factor;
		d_Y *= t_factor;
	}

	/*************************************************************************
	Operators
	*************************************************************************/
	point_type& operator*=
		(const point_type& _point) {
			d_X *= _point.d_X;
			d_Y *= _point.d_Y;

			return *this;
	}

	point_type& operator/=
		(const point_type& _point) {
			d_X /= _point.d_X;
			d_Y /= _point.d_Y;

			return *this;
	}

	point_type& operator+=
		(const point_type& _point) {
			d_X += _point.d_X;
			d_Y += _point.d_Y;

			return *this;
	}

	point_type& operator-=
		(const point_type& _point) {
			d_X -= _point.d_X;
			d_Y -= _point.d_Y;

			return *this;
	}

	point_type operator+
		(const point_type& _point)const {
			return point_type(d_X+_point.d_X, d_Y + _point.d_Y);
	}

	point_type operator-
		(const point_type& _point)const {
			return point_type(d_X-_point.d_X, d_Y-_point.d_Y);
	}

	point_type operator*
		(const point_type& _point)const {
			return point_type(d_X*_point.d_X, d_Y*_point.d_Y);
	}

	point_type operator*( float _fValue ) const{
		return point_type( _fValue*d_X, _fValue*d_Y );
	}

	bool operator==
		(const point_type& _point)const {
			return ((d_X==_point.d_X)&&(d_Y==_point.d_Y));
	}
	bool operator>
		(const point_type& _point)const {
			return ((d_X>_point.d_X)||(d_Y>_point.d_Y));
	}
	bool operator<
		(const point_type& _point)const {
			return ((d_X<_point.d_X)||(d_Y<_point.d_Y));
	}
	bool operator!=
		(const point_type& _point)const {
			return (!operator==(_point));
	}

	template <typename T1>
	point_type operator*
		(T1 _fScale)const {
			return point_type(d_X*_fScale, d_Y*_fScale);
	}

	template <typename T1>
	point_type& operator*=
		( T1 _fScale ) {
			d_X *= _fScale;
			d_Y *= _fScale;

			return *this;
	}
	template <typename T1>
	point_type operator/
		(T1 _fScale)const {
			return point_type(d_X/_fScale, d_Y/_fScale);
	}
	template <typename T1>
	point_type& operator/=
		( T1 _fScale ) {
			d_X /= _fScale;
			d_Y /= _fScale;

			return *this;
	}
	/*************************************************************************
	Data Fields
	*************************************************************************/

	T d_X, d_Y;
};

template <typename T>
class CTSize
{
public:
	typedef T value_type;

	/*!
	\brief
	Constructor for a Size.
	*/
	CTSize(void)	{ }
	CTSize(T _width, T _height):d_Width(_width), 
		d_Height(_height){}

	/*************************************************************************
	Data Fields
	*************************************************************************/

	T d_Width, d_Height;
};

/*!
\brief
template class CTRect description a rectangle,
that include the d_Top,d_Bottom,d_Left,d_Right of the
rectangle.
*/

template <typename T>
class CTRect
{
	typedef CTPoint2D<T> point_type;
	typedef CTSize<T>	 size_type;
	typedef CTRect<T>	 rect_type;

public:
	typedef T value_type;
	/*!
	\brief
	Constructor for a rect.
	*/

	CTRect(void) { }

	CTRect(T& _t) : d_Top(_t), d_Bottom(_t), d_Left(_t), d_Right(_t){
	}
	CTRect(T _Left, T _Top, T _Right, T _Bottom)
		:d_Left(_Left), d_Top(_Top), d_Right(_Right), 
		d_Bottom(_Bottom) { }

	/*!
	\brief
	Destructor for a rect.
	*/
	~CTRect(void) {}

	/*!
	\brief
	return width of rect area

	*/

	T getWidth(void)const { return d_Right-d_Left;}

	/*!
	\brief
	return height of rect area

	*/
	T getHeight(void)const { return d_Bottom - d_Top;}

	/*!
	\brief
	return left top corner coordinate of the rect area

	*/

	point_type getLeftTopPos(void) const	{
		return point_type(d_Left, d_Top);
	}

	/*!
	\brief
	return left bottom corner coordinate of the rect area

	*/
	point_type getLeftBottomPos(void) const	{
		return point_type(d_Left, d_Bottom);
	}

	/*!
	\brief
	return right bottom corner coordinate of the rect area

	*/
	point_type getRightBottomPos(void) const	{
		return point_type(d_Right, d_Bottom);
	}

	/*!
	\brief
	return right top corner coordinate of the rect area

	*/
	point_type getRightTopPos(void) const	{
		return point_type(d_Right, d_Top);
	}

	/*!
	\brief
	return the center point of rect area

	*/
	point_type getCenterPt(void) const {
		return point_type( d_Left + getWidth()/T(2), 
			d_Bottom + getHeight()/T(2));
	}

	/*!
	\brief
	return the size of the rect area

	*/
	size_type getSize(void)const {
		return size_type(getWidth(), getHeight());
	}

	/*!
	\brief
	set the width of the rect object
	*/
	void setWidth(T _width)	{ d_Right = d_Left + _width; }

	/*!
	\brief
	set the height of the rect object
	*/
	void setHeight(T _height)	{ d_Bottom = d_Top + _height; }

	/*!
	\brief
	set the size of the rect area
	*/
	void setSize(const size_type& _size) {
		setWidth(_size.d_Width);
		setHeight(_size.d_Height);
	}

	/*!
	\brief
	set the position of the rect (leaves size in tact)
	*/

	void setPos(const point_type& _pt)		{
		size_type t_sz(getSize());

		d_Left    = _pt.d_X;
		d_Bottom  = _pt.d_Y;
		setSize(t_sz);
	}

	/*!
	\brief
	Moves rect to the specified x-coordinates
	*/
	void moveToX(const T _x)	{
		size_type t_size(getSize());

		d_Left = _x;
		setSize(t_size);
	}

	/*!
	\brief
	Moves rect to the specified y-coordinates
	*/
	void moveToY(const T _y)	{
		size_type t_size(getSize());

		d_Bottom = _y;
		setSize(t_size);
	}

	/*!
	\brief
	Moves rect to the x and y-coordinates
	*/
	void moveToXY(const point_type& _point) {
		size_type t_size(getSize());

		d_Left   = _point.d_X;
		d_Bottom = _point.d_Y;
		setSize(t_size);
	}

	/*!
	\brief
	return a rect that is the intersection of 'this' rect with the rect '_rect'

	\note
	It can be assumed that if d_left == d_right, or d_top == d_bottom, or getWidth() == 0, or getHeight() == 0, then
	'this' rect was totally outside '_rect'.
	*/
	rect_type getIntersection
		(const rect_type& _rect)const	
	{
		if ((d_Right>_rect.d_Left) &&
			(d_Left<_rect.d_Right) &&
			(d_Top<_rect.d_Bottom) &&
			(d_Bottom>_rect.d_Top)) 
		{
			return rect_type(
				(d_Left>_rect.d_Left) ? d_Left:_rect.d_Left,
				(d_Top>_rect.d_Top) ? d_Top:_rect.d_Top,
				(d_Right<_rect.d_Right) ? d_Right:_rect.d_Right,
				(d_Bottom<_rect.d_Bottom) ? d_Bottom:_rect.d_Bottom);
		}

		return rect_type(0, 0, 0, 0);
	}

	rect_type& constrainSize(const size_type& Max, 
		const size_type& Min)	
	{
		size_type curr(getSize());

		if (curr.Width > Max.Width)
		{
			setWidth(Max.Width);
		}
		else if (curr.Width < Min.Width)
		{
			setWidth(Min.Width);
		}

		if (curr.Height > Max.Height)
		{
			setHeight(Max.Height);
		}
		else if (curr.Height < Min.Height)
		{
			setHeight(Min.Height);
		}

		return *this;
	}

	/*!
	\brief
	Applies an _offset the rect object

	\param _delta
	Point object containing the offsets to be applied to the rect.

	\return
	this rect after the _offset is performed
	*/

	rect_type& _offset(const point_type& _delta) {
		d_Left   += _delta.d_X;
		d_Right  += _delta.d_X;
		d_Top	 += _delta.d_Y;
		d_Bottom += _delta.d_Y;

		return *this;
	}

	/*!
	\brief
	Return true if the given Point falls within this rect

	\param _pt
	Point object describing the position to test.

	\return
	true if position  _pt is within this Rect's area, else false
	*/

	bool isPtInRect(const point_type& _pt) const	{
		if ((d_Left <= _pt.d_X) && (d_Right  > _pt.d_X) &&
			(d_Top  <= _pt.d_Y) && (d_Bottom > _pt.d_Y))
		{
			return true;
		}

		return false;
	}

	/*************************************************************************
	Operators
	*************************************************************************/
	bool operator== (const rect_type& r) const {
		return ((d_Top == r.d_Top) && (d_Bottom == r.d_Bottom) 
			&& (d_Left == r.d_Left) && (d_Right == r.d_Right));
	}

	bool operator!= (const rect_type& r) const {
		return !operator==(r);
	}

	/*************************************************************************
	Data Fields
	*************************************************************************/
	T d_Top, d_Bottom, d_Left, d_Right;

};

typedef CTPoint2D<int>	        CGPoint;
typedef CTRect<int>		        CGRect;

inline bool GPtInRect(int _iX,int _iY,const CGRect& _r)
{
	bool ret =  !(_iX<_r.d_Left||_iX>_r.d_Right-1||_iY>_r.d_Bottom||_iY<_r.d_Top-1);
	
	//if ( _iX < _r.d_Left && _iY>_r.d_Top-1 )
	//{
	//	ret = false;
	//}
	//else if ( _iX>_r.d_Right-1 && )
	//{
	//}
	return ret;
}
#endif//__GMATH_H__

